package tatrus;

import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import javax.swing.JFrame;
import javax.swing.JList;

/**
 * <p>Title: HighScoreManager </p>
 * <p>Description: CSIS 343 Course Project</p>
 * 
 * The purpose of this class is to provide a means to access the 
 * database used to store the top 10 high scores achieved by players.   
 * 
 * @author Nick Brown
 * @email  nicholas.brown@my.uwrf.edu
 * @author John Wagner 
 * @email  john.wagner@my.uwrf.edu
 * 
 * @date November 28th 2013
 *
 */

public class HighScoreManager extends JFrame implements WindowListener
{
	private static final long serialVersionUID = 400L;
	public static final String PERSISTENCE_UNIT_NAME = "HighScoresTable";
	public static final int X_OFFSET = 1050;
	public static final int Y_OFFSET = 420;
	public static final int FRAME_WIDTH = 195;
	public static final int FRAME_HEIGHT = 223;
	public static final int LIST_OFFSET = 7;
	public static final int LIST_WIDTH = 175;
	public static final int LIST_HEIGHT = 182;
	
	private List<?> tempList;	
	private ArrayList<HighScore> queryResults;	
	private JList<HighScore> listView;
	private Vector<HighScore> scoreList;
	private EntityManagerFactory emFactory;
	private EntityManager entityManager; 
	private Query query;  
	private Game game;
	
	
	/**
	 * Creates a new HighScoreManager used to handle the
	 * database operations for HighScore objects.  
	 * 
	 * @param game The Game object controlling the game
	 */
	public HighScoreManager(Game game)
	{
		this.game = game;
		
		emFactory = Persistence.createEntityManagerFactory(
												PERSISTENCE_UNIT_NAME);
		
		entityManager = emFactory.createEntityManager();
		
		setTitle("High Scores");
        setLayout(null);
        setBounds(X_OFFSET, Y_OFFSET, FRAME_WIDTH, FRAME_HEIGHT);
        setResizable(false);
		setVisible(false);
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		
		/* Adding a WindowListener to the object so that appropriate
		 * action can be taken when a closing event takes place.  
		 */
		addWindowListener(this);
	}
	
	/**
	 * Queries the database and retrieves all of the HighScore 
	 * objects contained within it, up to a maximum of 10. 
	 */
	public void getHighScores()
	{
		query = entityManager.createQuery(
				   "select distinct h from HighScore h order by h.score desc");
		
		tempList = query.getResultList();
		
		queryResults = new ArrayList<HighScore>();
		
		/* Casting and transferring the HighScore objects
		 * returned by the query from the raw list to
		 * an arrayList.  
		 */
		for(Object object: tempList)
		{
			queryResults.add((HighScore) object);
		}
		
		scoreList = new Vector<HighScore>();
		
		
		/* Copying the HighScore objects from the arrayList
		 * to a Vector which will eventually be passed to 
		 * the JList constructor so that all names and
		 * corresponding high scores can be displayed.
		 */
		if(queryResults != null)
		{
			for(HighScore highScore: queryResults)
			{
				scoreList.add(highScore);
			}
		}
	}
	
	/**
	 * Queries the database to find out how many 
	 * HighScore objects it currently contains.  
	 * 
	 * @return The number of HighScore objects in the database
	 */
	public long getHighScoreCount()
	{
		query = entityManager.createQuery("select count (h) from HighScore h");
		
		long count = (long) query.getSingleResult();
		
		return count;
	}
	
	/**
	 * Adds the HighScore object which is passed
	 * as the parameter to the database.  
	 * 
	 * @param highScore The HighScore object to be added
	 */
	public void insertHighScore(HighScore highScore)
	{
		entityManager.getTransaction().begin();
		    
		entityManager.persist(highScore);

		entityManager.getTransaction().commit();
	}
	
	/**
	 * Finds the lowest score in the database and removes it.
	 */
	public void deleteLowestScore()
	{
		query = entityManager.createQuery(
				"select distinct h from HighScore h order by h.score");

		tempList = query.getResultList();
		
		queryResults = new ArrayList<HighScore>();
		
		/* Casting and transferring the HighScore objects
		 * returned by the query from the raw list to
		 * an arrayList.  
		 */
		for(Object object: tempList)
		{
			queryResults.add((HighScore) object);
		}
		
		// Retrieving and removing the lowest score
		HighScore lowest = queryResults.get(0);
		
		entityManager.getTransaction().begin();
		    
		entityManager.remove(lowest);
		
		entityManager.getTransaction().commit();
	}
	
	/**
	 * Takes the Vector of HighScore objects and passes 
	 * it to the JList constructor so that the high 
	 * scores are available for viewing.  
	 */
	public void setScoreList()
	{
		getHighScores();
		listView = new JList<HighScore>(scoreList);
		listView.setBounds(LIST_OFFSET, LIST_OFFSET, LIST_WIDTH, LIST_HEIGHT);   
		add(listView);
	}
	
	/**
	 * Sets the visibility of the JFrame.
	 * 
	 * @param isVisible true if the Frame is to be visible, otherwise false
	 */
	public void setFrameVisibility(boolean isVisible)
	{
		setVisible(isVisible);
	}
	
	/**
	 * Determines whether or not the score passed as the parameter
	 * is greater than any of the current top 10 scores.
	 * 
	 * @param score The score to be checked
	 * 
	 * @return true if the score is higher than any 
	 * 		   of the current top 10 scores, otherwise false
	 */
	public boolean isHighScore(int score)
	{
		getHighScores();
		
		for(HighScore highScore: queryResults)
		{
			if(score > highScore.getScore())
			{
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Method inherited from the WindowListener interface,
	 * which is called when this frame is disposed.  Used 
	 * to ensure only one instance of the HighScoreManager
	 * class is running at any given time.    
	 */
	public void windowClosed(WindowEvent event)
	{
		game.setScoreManagerClosed();
	}
	
	// Unimplemented methods inherited from the WindowListener interface
	
	public void windowClosing(WindowEvent event) {}
	
	public void windowActivated(WindowEvent event) {}
	
	public void windowDeactivated(WindowEvent event) {}
	
	public void windowDeiconified(WindowEvent event) {}
	
	public void windowOpened(WindowEvent event) {}
	
	public void windowIconified(WindowEvent event) {}
}